package twi.query.template;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.swing.SwingUtilities;

import twi.filter.DropAnonFilter;
import twi.query.SparqlQuery;
import twi.query.template.view.IndividualPropertiePanel;
import twi.query.template.view.IndividualSinglePropertyPanel;
import twi.query.template.view.TemplateMainView;
import twi.result.table.RTable;
import twi_project.TWI;

import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntProperty;
import com.hp.hpl.jena.ontology.OntResource;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.vocabulary.RDF;

public class Template implements Serializable{

	public static final String INDIVIDUAL = "individual";
	private TemplateMainView mainView = null;
	ArrayList<TemplateNode> rootNodes = new ArrayList<TemplateNode>();
	private String templateName;
	private String templateDescription;
	
	public Template(TemplateMainView tmv){
		this.mainView = tmv;
	}
	
	public void createRootNode(){
		this.mainView.getTreePanel().layout = true;
		List list = TWI.getInstance().getOntologieModel().listHierarchyRootClasses().filterDrop(new DropAnonFilter()).toList();
		ArrayList<String> cl = new ArrayList<String>();
		for (int i = 0; i < list.size(); i++)
			if (list.get(i) instanceof OntClass)
				cl.add(((OntClass)list.get(i)).getLocalName());
		ClassNode cn = new ClassNode(null, cl, this, null);
		this.rootNodes.add(cn);
		mainView.getTreePanel().add(cn);
		doLayout();
	}
	public void init(TemplateMainView mv){
		this.mainView = mv;
		mv.getTreePanel().layout = true;
		for (int i = 0; i  <rootNodes.size(); i++)
			((ClassNode)rootNodes.get(i)).init(mv);
		doLayout();
	}
	public void doLayout(){
		SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				mainView.getTreePanel().layoutTree();
				mainView.validate();
			}
		});
	}

	public void updateNodes(ClassNode cn, OntProperty prop, boolean newNode, boolean isDomain) {
		ClassNode maxim = null;
		if (newNode ){
			List list = null;
			if (isDomain)
				list = prop.listRange().toList();
			else
				list = prop.listDomain().toList();

			ArrayList<String> nameList = new ArrayList<String>();
			for (int i = 0; i < list.size(); i++){
				OntResource r = (OntResource) list.get(i);
				try{
					nameList.addAll(getLocalName(r));
					nameList.addAll(getSubClassNames(r));
//					nameList.addAll(getIndividualNames(r));
				}catch (Exception e) {
					e.printStackTrace();
				}
			}
			ClassNode nn = new ClassNode(cn, nameList, this, prop);
			maxim = nn;
		}else{
			for (int i = 0; i < cn.getChildCount(); i++){
				Property p = ((ClassNode)cn.getChild(i)).getPropertie();
				if (p == null)
					continue;
				if (p == prop){
					cn.getChild(i).deepRemove();
					cn.removeChild(i);
				}
			}
			maxim = cn;
		}
		setMaximized_Rek(maxim);
		doLayout();
	}

	private ArrayList<String> getLocalName(OntResource r) {
		String split[] = RTable.getNodeName(r).split(";");
		ArrayList<String> out = new ArrayList<String>();
		for (int i = 0; i <split.length; i++)
			out.add(split[i]);
		return out;
	}

	private ArrayList<String> getIndividualNames(OntResource r) {
		ArrayList<String> out = new ArrayList<String>();
		if (!(r instanceof OntClass))
			return out;
		OntClass cl = (OntClass)r;
		List inList = cl.listInstances(true).filterDrop(new DropAnonFilter()).toList();
		for (int i = 0; i<  inList.size(); i++){
			out.add(((Individual)inList.get(i)).getLocalName());
		}
		return out;
	}

	private ArrayList<String> getSubClassNames(OntResource r) {
		ArrayList<String> out = new ArrayList<String>();
		if (!(r instanceof OntClass))
			return out;
		OntClass cl = (OntClass)r;
		List subList = cl.listSubClasses().filterDrop(new DropAnonFilter()).toList();
		for (int i = 0; i<  subList.size(); i++){
			out.add(((OntClass)subList.get(i)).getLocalName());
		}
		return out;
	}

	private void setMaximized_Rek(ClassNode maxim) {
		for (int i = 0; i < this.rootNodes.size(); i++){
			setMinimized_Rek(this.rootNodes.get(i));
		}
		maxim.setMaximized();
	}

	private void setMinimized_Rek(TemplateNode tn) {
		tn.setMinimized();
		for (int i = 0; i < tn.getChildCount(); i++)
			setMinimized_Rek((TemplateNode)tn.getChild(i));
	}

	public void minimizeAll() {
		for (int i = 0; i < this.rootNodes.size(); i++)
			this.setMinimized_Rek(this.rootNodes.get(i));
	}

	public void createIndividualNode(ClassNode classNode, String className) {
		OntClass cl = TWI.getInstance().getOntologieModel().getOntClass(className);
		ArrayList<String> individualNames = getIndividualNames(cl);
		individualNames.add(0, INDIVIDUAL);
		ClassNode cn = new ClassNode(classNode, individualNames, this, RDF.type); //TWI.getInstance().getOntologieModel().getOntProperty(RDF.type.getURI()));
		setMaximized_Rek(cn);
		doLayout();
	}

	public void removeRoot(ClassNode classNode) {
		this.rootNodes.remove(classNode);
	}

	class SaveDesc{

		public String className;
		public String variableName;
		
	}
	class SaveNode {
		ArrayList<SaveDesc> desc = new ArrayList<SaveDesc>();
	}
	
	public SparqlQuery createSparqlQuery(){
		ArrayList<String> parts = new ArrayList<String>();
		ArrayList<String> varList = new ArrayList<String>();
		for (int i =  0; i < this.rootNodes.size(); i++){
			SaveNode sn = new SaveNode();
			parts.add(sparqlQuery_rek((ClassNode) this.rootNodes.get(i), null, varList, null,sn));
		}
		String q = "SELECT ";
		for (int i = 0; i < varList.size(); i++)
			q += "?"+varList.get(i)+" ";
		q += "\nWHERE { \n" ;
		for (int i = 0; i< parts.size(); i++)
			q+=parts.get(i)+" \n";
		q+="}";
		SparqlQuery sq = new SparqlQuery(q, TWI.getInstance().getOntologieModel(), true);
		return sq;
	}



	private String sparqlQuery_rek(ClassNode cn, String parVar, ArrayList<String> varList, String prefProp, SaveNode sn) {
		OntClass currentClass = cn.getSelectedClass();
		if (currentClass != null){
			return sparqlQuery_rekClass(cn, parVar, varList, currentClass, prefProp, sn);
		}
		if (cn.isDatatypeOnly()){
			if (cn.isAsVariable())
				return "";
			IndividualSinglePropertyPanel panel = ((IndividualPropertiePanel)cn.getPanel().getHidePanel()).getPropertiePanels().get(0);
			String value = panel.getSearchValue();
			return "?"+parVar+" "+cn.getPropertie().getURI()+" \""+value+"\".\n";
		}else if (cn.isIndividual()){
			OntClass t1 = cn.getSelectedClass();
			Individual t2 = cn.getSelectedIndividual();
			return handleIndi2(cn, parVar);
		}
	
		return "\n";
	}

	private String handleIndi2(ClassNode indi, String varName) {
		IndividualPropertiePanel panel = (IndividualPropertiePanel) indi.getPanel().getHidePanel();
		if (panel == null)
			return "";
		ArrayList<IndividualSinglePropertyPanel> singlePropPanelList = panel.getPropertiePanels();
		String p1 = "";
		for (int i = 0; i < singlePropPanelList.size(); i++){
			if (singlePropPanelList.get(i).isSelected()){
				String searchValue 	= singlePropPanelList.get(i).getSearchValue().trim();
				String properyName 	= singlePropPanelList.get(i).getPropertyName();
				String operator		= singlePropPanelList.get(i).getOperator();
//				Property prop1 = TWI.getInstance().getOntologieModel().getProperty(properyName);
//				if (prop1 == null)
//					continue;
				properyName = TWI.getInstance().getOntologieModel().getBasePrefix()+properyName;
				OntClass r = TWI.getInstance().getOntologieModel().getOntClass(searchValue);
				String c = null;
				if (r != null){
					c = r.getURI();
				}else{
					Individual r1 = TWI.getInstance().getOntologieModel().getIndividual(searchValue);
					if (r1 != null)
						c = r1.getURI();
					else 
						c = "\""+searchValue+"\"";
				}
					
				p1 += "?"+varName + " "+properyName+" " + c + ".\n";
			}
		}
		return p1;
	}

	private String sparqlQuery_rekClass(ClassNode cn, String parVar,
			ArrayList<String> varList, OntClass currentClass, String prefProp, SaveNode sn) {
		String className = currentClass.getURI();
		String variableName = cn.getVariableName();
		SaveDesc sd = new SaveDesc();
		sn.desc.add(sd);
		sd.className = className;
		sd.variableName = variableName;
		
		if (!varList.contains(variableName) && cn.isShowResult())
			varList.add(variableName);
		String p1 = "";
		if (cn.isOptional()){
			p1 += "OPTIONAL {\n";
		}
		p1 += "?"+variableName + " "+RDF.type.getURI() +" "+className+".\n";
		for (int i = 0; i < cn.getChildCount(); i++){
			ClassNode child = (ClassNode) cn.getChild(i);
			Property prop = child.getPropertie();
			String varname = child.getVariableName();
			if (cn.isDomainProperty(prop))
				p1 += "?"+variableName + " "+prop.getURI()+" ?"+varname+".\n";
			else
				p1 += "?"+varname + " " + prop.getURI() + " ?"+variableName+".\n";
			if(child.isAsVariable()){
				if (!varList.contains(varname) )
					varList.add(varname);
			}
			//Auf individuen testen
			for (int j = 0; j < child.getChildCount(); j++){
				if (((ClassNode)child.getChild(j)).isIndividual()){
					ClassNode indi = ((ClassNode)child.getChild(j));
					
					String varN = indi.getPanel().getVariableName();
					String classN = indi.getPanel().getClassName();
					OntResource r = TWI.getInstance().getOntologieModel().getIndividual(classN);
					if (r == null)
						p1 += handleIndividual(indi, prop, variableName, varList);
					else{
						p1+= "?"+variableName + " " + prop.getURI() + " "+r.getURI()+".\n";
					}
				}
			}
			
			
			
			
			p1 += sparqlQuery_rek(child, variableName, varList, prefProp, sn);
			
		}
		if (cn.isOptional()){
			p1 += "}";
		}
		return p1;
	}

	private String handleIndividual(ClassNode indi, Property prop,
			String variableName, ArrayList<String> varList) {
		String varName = indi.getVariableName();
		varList.add(varName);
		String p1 = "?"+variableName+" "+prop.getURI()+" ?"+varName+".\n";
		
		
		IndividualPropertiePanel panel = (IndividualPropertiePanel) indi.getPanel().getHidePanel();
		ArrayList<IndividualSinglePropertyPanel> singlePropPanelList = panel.getPropertiePanels();
		String p2 = "";
		for (int i = 0; i < singlePropPanelList.size(); i++){
			if (singlePropPanelList.get(i).isSelected()){
				String searchValue 	= singlePropPanelList.get(i).getSearchValue().trim();
				String properyName 	= singlePropPanelList.get(i).getPropertyName();
				String operator		= singlePropPanelList.get(i).getOperator();
//				Property prop1 = TWI.getInstance().getOntologieModel().getProperty(properyName);
//				if (prop1 == null)
//					continue;
				properyName = TWI.getInstance().getOntologieModel().getBasePrefix()+properyName;
				OntClass r = TWI.getInstance().getOntologieModel().getOntClass(searchValue);
				String c = null;
				if (r != null){
					c = r.getURI();
				}else{
					Individual r1 = TWI.getInstance().getOntologieModel().getIndividual(searchValue);
					if (r1 != null)
						c = r1.getURI();
					else 
						c = "\""+searchValue+"\"";
				}
					
				p1 += "?"+varName + " "+properyName+" " + c + ".\n";
			}
		}
		
		return p1;
	}

	public void setName(String name) {
		this.templateName = name;		
	}

	public void setDescription(String desc) {
		this.templateDescription = desc;
	}

	public String getTemplateName() {
		return templateName;
	}

	public void setTemplateName(String templateName) {
		this.templateName = templateName;
	}

	public String getTemplateDescription() {
		return templateDescription;
	}

	public void setTemplateDescription(String templateDescription) {
		this.templateDescription = templateDescription;
	}
}
